package com.github.xiaolyuh.flush;


import com.github.xiaolyuh.configcenter.ConfigCenter;
import com.github.xiaolyuh.entity.RedisName;
import com.github.xiaolyuh.exception.PromotionMonitorException;
import com.github.xiaolyuh.util.StringUtils;
import com.github.xiaolyuh.utils.FastJSONHelper;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;

import static com.github.xiaolyuh.RedisKeyVersionManager.batchGetRedisVersion;
import static com.github.xiaolyuh.RedisKeyVersionManager.getKeys;

public abstract class AbstractLocalCacheFlushManager implements ILocalCacheFlushManager {

    private static final Logger logger = LoggerFactory.getLogger(AbstractLocalCacheFlushManager.class);

    private static final Cache<String, String> LOCAL_VERSIONS = CacheBuilder.newBuilder().maximumSize(300000L)
            //缓存7天
            .expireAfterAccess(7, TimeUnit.DAYS)
            .concurrencyLevel(Math.max(12, Runtime.getRuntime().availableProcessors()))
            .build();

    @Override
    public void flush(RedisName redisName) {
        if (!ConfigCenter.allowLocalCache()) {
            return;
        }
        Set<String> redisKeys = Sets.newHashSet();
        try {
            redisKeys = getKeys(redisName);
        } catch (Exception e) {
            logger.error("[flush local cache]query redis version error", PromotionMonitorException.of(e));
        }
        if (redisKeys.isEmpty()) {
            return;
        }
        Map<String, String> clearKeys = Maps.newHashMap();
        Map<String, String> redisVersions = batchGetRedisVersion(redisName, redisKeys);
        for (String key : redisKeys) {
            String redisKeyVersion = redisVersions.get(key);
            if (StringUtils.isBlank(redisKeyVersion)) {
                continue;
            }
            String localKeyVersion = LOCAL_VERSIONS.getIfPresent(key);
            if (!redisKeyVersion.equals(localKeyVersion)) {
                clearKeys.put(key, redisKeyVersion);
            }
        }
        // 清除本地缓存
        if (!clearKeys.isEmpty()) {
            clear(clearKeys.keySet());
            LOCAL_VERSIONS.putAll(clearKeys);
            logger.info("[flush local cache]clear local keys={}", FastJSONHelper.serialize(clearKeys));
        }
        clearKeys.clear();
        redisKeys.clear();
        redisVersions.clear();
    }

    /**
     * 清除本地缓存
     *
     * @param keyList
     */
    public abstract void clear(Set<String> keyList);

}
